package com.example.springbootdemo.websocket;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * websocket服务端
 * @author hh
 * @date 2022/2/28
 */
@Slf4j
@Component
@ServerEndpoint("/websocket/{id}")
public class WebSocketServer {

    /**
     * 全部在线会话  PS: 基于场景考虑 这里使用线程安全的Map存储会话对象。
     */
    private static Map<String, Session> onLineSessions = new ConcurrentHashMap<>();

    /**
     * 当客户端打开连接：1.添加会话对象，2.更新在线人数
     * @param session session
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("id") String id){
        log.info("[{}]上线了", id);
        onLineSessions.put(session.getId(), session);
        sendMessageToAll(session.getId(), id + "上线了，目前在线人数：" + onLineSessions.size());
    }

    /**
     * 接收到客户端发送的消息
     * @param session session
     * @param msg msg
     */
    @OnMessage
    public void onMessage(Session session, String msg){
        log.info("服务端接受到消息：[{}]{}", session.getId(), msg);
        sendMessageToAll(session.getId(), msg);
    }

    /**
     * 关闭连接
     * @param session session
     */
    @OnClose
    public void onClose(Session session, @PathParam("id") String id){
        log.info("[{}]下线了,目前在线人数[{}]", id, onLineSessions.size());
        onLineSessions.remove(session.getId());
        sendMessageToAll(session.getId(), session.getId()+ "下线了,目前在线人数：" + onLineSessions.size());
    }

    /**
     * 当通信发生异常，打印错误日志
     * @param error error
     */
    @OnError
    public void onError(Throwable error){
        log.error("通信异常", error);
    }

    /**
     * 发送消息给某一个人
     * @param id id
     * @param msg 消息
     */
    private void sendMessageToOne(String id, String msg){
        Session session = onLineSessions.get(id);
        if (Objects.nonNull(session)){
            try {
                session.getBasicRemote().sendText(msg);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 发布消息给所有人
     * @param tempId id
     * @param msg 消息
     */
    private void sendMessageToAll(String tempId, String msg) {
        onLineSessions.forEach((id, session) -> {
            if (!Objects.equals(id, tempId)){
                try {
                    session.getBasicRemote().sendText(msg);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    }

}
